#include "ThreadPool.h"
#include <algorithm>

ThreadPool::ThreadPool(size_t initialThreads, size_t maxThreads)
    : maxThreads_(maxThreads ? maxThreads : std::thread::hardware_concurrency() * 2),
      stop_(false) {
    if (initialThreads <= 0) initialThreads = 1;
    initialThreads = std::min(initialThreads, maxThreads_);
    
    workers_.reserve(maxThreads_);
    for (size_t i = 0; i < initialThreads; ++i) {
        workers_.emplace_back(&ThreadPool::workerFunction, this);
    }
}

ThreadPool::~ThreadPool() {
    stop_ = true;
    condition_.notify_all();
    for (auto& worker : workers_) {
        if (worker.joinable()) worker.join();
    }
}

void ThreadPool::resize(size_t newSize) {
    std::unique_lock<std::mutex> lock(queueMutex_);
    newSize = std::min(newSize, maxThreads_);
    while (workers_.size() < newSize) {
        workers_.emplace_back(&ThreadPool::workerFunction, this);
    }
}

size_t ThreadPool::getThreadCount() const {
    std::unique_lock<std::mutex> lock(queueMutex_);
    return workers_.size();
}

void ThreadPool::workerFunction() {
    while (!stop_) {
        std::function<void()> task;
        {
            std::unique_lock<std::mutex> lock(queueMutex_);
            condition_.wait(lock, [this]() { return stop_ || !tasks_.empty(); });

            if (stop_ && tasks_.empty()) return;

            if (!tasks_.empty()) {
                ++activeWorkers_;
                task = std::move(tasks_.front());
                tasks_.pop();
            }
        }

        if (task) {
            task();
            --activeWorkers_;
        }
    }
}

bool ThreadPool::tryAddWorker() {
    std::unique_lock<std::mutex> lock(queueMutex_, std::try_to_lock);
    if (!lock || workers_.size() >= maxThreads_) return false;
    
    workers_.emplace_back(&ThreadPool::workerFunction, this);
    return true;
}